﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using Estructuras.Estructura;
using Estructuras.Comunes;
using Estructuras.Funciones.BaseDatos;

namespace Estructuras.Funciones.BaseDatos.SqlServer
{
    public static partial class Ejecutar
    {
        /// <summary>
        /// Ejecuta un fichero con sentencias SQL por cada registro de entrada.
        /// Reemplaza los valores designados como %?NOMBRE% por el valor del campo NOMBRE para cada registro de la entrada.
        /// </summary>
        /// <param name="entrada">Fichero de entrada de datos</param>
        /// <param name="cadenaConexion">Cadena de conexión con la base de datos</param>
        /// <param name="ficheroSQL">Fichero con el código SQL a ejecutar</param>
        /// <param name="formatoEntrada">Estructura de los datos de entrada</param>
        /// <returns>Número de filas procesadas</returns>
        public static long EjecutarSQL(TextReader entrada, TextReader ficheroSQL, string cadenaConexion, Estructura.Estructura formatoEntrada)
        {
            SqlConnection conn;
            // Abre la conexión con la BBDD
            try
            {
                conn = new SqlConnection(cadenaConexion);
                conn.Open();
            }
            catch (Exception ex)
            {
                throw new Excepcion(Constantes.ErrorAbrirConexionBBDD + ex.Message, Constantes.CodigoErrorAbrirConexionBBDD);
            }
            try
            {
                long filasProcesadas = 0;
                // Obtiene el contenido del fichero SQL
                string sql = ficheroSQL.ReadToEnd();
                SqlCommand comando = conn.CreateCommand();
                SqlTransaction tran = conn.BeginTransaction();

                // Ejecuta la sentencia sql por cada línea de entrada
                string linea = entrada.ReadLine();
                while (linea != null)
                {
                    string sqlTemp = sql;
                    if (linea.Length != formatoEntrada.LongitudRegistro)
                        throw new Excepcion(Constantes.ErrorLongitudRegistroYFormatoNoCoinciden, Constantes.CodigoErrorLongitudRegistroYFormatoNoCoinciden);

                    // Reemplaza el valor %?NOMBRE_CAMPO% por el valor en el fichero
                    foreach (string campo in formatoEntrada.obtenerCampos())
                    {
                        string valor = formatoEntrada.obtenerValorCampo(linea, campo).TrimEnd();
                        sqlTemp = sqlTemp.Replace("%?" + campo.ToUpper() + "%", valor);
                        sqlTemp = sqlTemp.Replace("%?" + campo + "%", valor);
                        sqlTemp = sqlTemp.Replace("%?" + campo.ToLower() + "%", valor);
                    }
                    comando.CommandText = sqlTemp;

                    // Ejecuta el comando sql
                    try
                    {
                        comando.Transaction = tran;
                        comando.ExecuteNonQuery();
                    }
                    catch (Exception ex)
                    {
                        tran.Rollback();
                        throw new Excepcion(Constantes.ErrorEjecutarSQLBBDD + ex.Message, Constantes.CodigoErrorEjecutarSQLBBDD);
                    }
                    filasProcesadas++;
                    linea = entrada.ReadLine();
                }

                tran.Commit();

                // Cierra la conexión con la BBDD
                try
                {
                    conn.Close();
                    conn.Dispose();
                }
                catch (Exception ex)
                {
                    throw new Excepcion(Constantes.ErrorCerrarConexionBBDD + ex.Message, Constantes.CodigoErrorCerrarConexionBBDD);
                }

                return filasProcesadas;
            }
            catch (Excepcion ex)
            {
                if (conn.State != ConnectionState.Closed)
                {
                    conn.Close();
                    conn.Dispose();
                }
                throw ex;
            }
            catch (Exception ex)
            {
                if (conn.State != ConnectionState.Closed)
                {
                    conn.Close();
                    conn.Dispose();
                }
                throw new Excepcion(Constantes.ErrorEjecutarSQL + ex.Message, Constantes.CodigoErrorEjecutarSQL);
            }
        }
    }
}
